{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Quantum Development Kit Samples<br>Diagnostics: Facts and Assertions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Preamble"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We use the Microsoft.Quantum.Standard.Visualization package to provide additional visualization support for the diagnostics in this notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "{\"LastUpdated\":\"2020-08-25T21:25:10.6664721-07:00\",\"IsCompleted\":true,\"Description\":\"Adding package Microsoft.Quantum.Standard.Visualization\",\"Subtask\":\"done\"}",
      "text/plain": [
       "Adding package Microsoft.Quantum.Standard.Visualization: done!"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/json": "[\"Microsoft.Quantum.Standard::0.12.20082513\",\"Microsoft.Quantum.Standard.Visualization::0.12.20082513\"]",
      "text/html": [
       "<ul><li>Microsoft.Quantum.Standard::0.12.20082513</li><li>Microsoft.Quantum.Standard.Visualization::0.12.20082513</li></ul>"
      ],
      "text/plain": [
       "Microsoft.Quantum.Standard::0.12.20082513, Microsoft.Quantum.Standard.Visualization::0.12.20082513"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%package Microsoft.Quantum.Standard.Visualization"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For convinence, we'll also open the [Microsoft.Quantum.Diagnostics namespace](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics) so that its functions and operations are available throughout the notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[]",
      "text/html": [
       "<ul></ul>"
      ],
      "text/plain": []
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "open Microsoft.Quantum.Diagnostics;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Facts: Conditions on values"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Q# standard libraries provide several different ways to validate the correctness of quantum programs as functions and operations in the [Microsoft.Quantum.Diagnostics namespace](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics).\n",
    "The first and most basic of these are *facts*, which represent an invariant that always holds for a given value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[\"AdditionFact\"]",
      "text/html": [
       "<ul><li>AdditionFact</li></ul>"
      ],
      "text/plain": [
       "AdditionFact"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "function AdditionFact() : Unit {\n",
    "    Fact(2 + 3 == 5, \"addition fact failed\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "{\"@type\":\"tuple\"}",
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%simulate AdditionFact"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "From this example, you can see that when a fact is true, nothing happens. On the other hand, if the condition for a fact fails, then the Q# program is terminated with the message associated with the fact. Try modifying the example above and see what happens when you run `%simulate AdditionFact` again."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One important thing to note is that facts depend only on *values*. That is, `2 + 3 == 5` is a value of type `Bool` that is either `true` or `false` irrespective of the state of your target machine, or of any qubits in your device. As a consequence, facts can be expressed as functions that are easy to use either in other functions, or in adjointable and controllable operations. For example, let's take a quick look at how the [`Fact` function](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics.fact) is defined in the Q# standard libraries:\n",
    "\n",
    "```qsharp\n",
    "function Fact(actual : Bool, message : String) : Unit {\n",
    "    if (not actual) { fail message; }\n",
    "}\n",
    "```\n",
    "\n",
    "Similarly, the [`Microsoft.Quantum.Diagnostics.Contradiction` function](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics.contradiction) function can be used to ensure that a value is definitely `false` at some point in a Q# program:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[\"AdditionContradiction\"]",
      "text/html": [
       "<ul><li>AdditionContradiction</li></ul>"
      ],
      "text/plain": [
       "AdditionContradiction"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "function AdditionContradiction() : Unit {\n",
    "    Contradiction(2 + 3 == 6, \"addition contradiction failed\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "{\"@type\":\"tuple\"}",
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%simulate AdditionContradiction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In practice, it can be helpful to test conditions that have more structure than a `Bool` value, such as that two values are equal to each other. This allows for printing out helpful information when things go wrong; let's try that out by updating our definition of `AdditionFact` to something incorrect and see what happens:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[\"AdditionFact\"]",
      "text/html": [
       "<ul><li>AdditionFact</li></ul>"
      ],
      "text/plain": [
       "AdditionFact"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "function AdditionFact() : Unit {\n",
    "    // This should fail, since it is decidedly not a fact that 2 + 3 is equal to 6.\n",
    "    EqualityFactI(2 + 3, 6, \"addition fact failed\");\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "{\"Exception\":{\"StackTrace\":\"   at Microsoft.Quantum.Diagnostics.FormattedFailure`1.<>c.<get_Body>b__7_0(ValueTuple`3 __in__) in D:\\\\a\\\\1\\\\s\\\\submodules\\\\QuantumLibraries\\\\Standard\\\\src\\\\Diagnostics\\\\Internal.qs:line 14\\r\\n   at Microsoft.Quantum.Simulation.Core.Function`2.Apply(I a)\\r\\n   at Microsoft.Quantum.Simulation.Core.Function`2.Apply[GenO](Object args)\\r\\n   at Microsoft.Quantum.Simulation.Core.GenericCallable.Apply[O](Object args) in D:\\\\a\\\\1\\\\s\\\\submodules\\\\qsharp-runtime\\\\src\\\\Simulation\\\\Core\\\\Generics\\\\GenericCallable.cs:line 122\\r\\n   at Microsoft.Quantum.Simulation.Core.GenericCallable.Microsoft.Quantum.Simulation.Core.ICallable.Apply(Object args) in D:\\\\a\\\\1\\\\s\\\\submodules\\\\qsharp-runtime\\\\src\\\\Simulation\\\\Core\\\\Generics\\\\GenericCallable.cs:line 135\\r\\n   at Microsoft.Quantum.Diagnostics.EqualityFactI.<get_Body>b__11_0(ValueTuple`3 __in__) in D:\\\\a\\\\1\\\\s\\\\submodules\\\\QuantumLibraries\\\\Standard\\\\src\\\\Diagnostics\\\\Facts.qs:line 93\\r\\n   at Microsoft.Quantum.Simulation.Core.Function`2.Apply(I a)\\r\\n   at Microsoft.Quantum.Simulation.Core.Function`2.Microsoft.Quantum.Simulation.Core.ICallable<I,O>.Apply(I args)\\r\\n   at SNIPPET.AdditionFact.<get_Body>b__10_0(QVoid __in__)\\r\\n   at Microsoft.Quantum.Simulation.Core.Function`2.Apply(I a)\\r\\n   at Microsoft.Quantum.Simulation.Core.Function`2.Apply[GenO](Object args)\\r\\n   at Microsoft.Quantum.Simulation.Common.SimulatorBase.Execute[T,I,O](I args) in D:\\\\a\\\\1\\\\s\\\\submodules\\\\qsharp-runtime\\\\src\\\\Simulation\\\\Common\\\\SimulatorBase.cs:line 156\",\"Message\":\"addition fact failed\\n\\tExpected:\\t6\\n\\tActual:\\t5\",\"Data\":{},\"InnerException\":null,\"HelpLink\":null,\"Source\":\"Microsoft.Quantum.Standard\",\"HResult\":-2146233088},\"StackTrace\":null,\"Header\":\"Unhandled exception. Microsoft.Quantum.Simulation.Core.ExecutionFailException: addition fact failed\\n\\tExpected:\\t6\\n\\tActual:\\t5\"}",
      "text/plain": [
       "Microsoft.Quantum.IQSharp.DisplayableException"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "addition fact failed\n",
      "\tExpected:\t6\n",
      "\tActual:\t5\r\n"
     ]
    }
   ],
   "source": [
    "%simulate AdditionFact"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One particularly important example of when facts can be useful is in comparing the results we get from measuring a register of qubits to what we would expect to get based on the state we tried to prepare. For instance, consider the following operation to prepare a pair of entangled qubits (itself a special case of the [`PrepareEntangledState` operation](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.preparation.prepareentangledstate)):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[\"PrepareEntangledPair\"]",
      "text/html": [
       "<ul><li>PrepareEntangledPair</li></ul>"
      ],
      "text/plain": [
       "PrepareEntangledPair"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "operation PrepareEntangledPair(left : Qubit, right : Qubit) : Unit is Adj + Ctl {\n",
    "    H(left);\n",
    "    CNOT(left, right);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can check that this operation works the way would expect by checking some properties of its output state. In particular, we expect that this operation will prepare the state $\\left(\\left|00\\right\\rangle + \\left|11\\right\\rangle\\right) / \\sqrt{2}$ when given two qubits initially in the $\\left|00\\right\\rangle$ state. Thus, measuring the parity of the prepared state should always return `Zero`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[\"CheckEntanglementPreparation\"]",
      "text/html": [
       "<ul><li>CheckEntanglementPreparation</li></ul>"
      ],
      "text/plain": [
       "CheckEntanglementPreparation"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "operation CheckEntanglementPreparation() : Unit {\n",
    "    using ((left, right) = (Qubit(), Qubit())) {\n",
    "        PrepareEntangledPair(left, right);\n",
    "        let actual = Measure([PauliZ, PauliZ], [left, right]);\n",
    "        EqualityFactR(actual, Zero, \"Parity of (|00⟩ + |11⟩) / √2 was not Zero.\");\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "{\"@type\":\"tuple\"}",
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%simulate CheckEntanglementPreparation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For more examples, check out the list of fact functions in the [Microsoft.Quantum.Diagnostics namespace](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics) documentation."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Assertions: Conditions on machine state"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By comparison, we sometimes want to check a condition on the state of our machine or of some qubits within a device. Unlike facts, conditions of this form can't be represented as functions, since a condition on a `Qubit` value may be true or false depending on the side effects accumulated in a program so far — not just depending on the `Qubit` itself.\n",
    "\n",
    "Thus, conditions on states need to represented as *operations* rather than as *functions*. Let's take a look at how we can use operations to validate that freshly allocated qubits start off in the $\\left|0\\right\\rangle$ state:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[\"CheckFreshQubitIsInZero\"]",
      "text/html": [
       "<ul><li>CheckFreshQubitIsInZero</li></ul>"
      ],
      "text/plain": [
       "CheckFreshQubitIsInZero"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "operation CheckFreshQubitIsInZero() : Unit {\n",
    "    using (q = Qubit()) {\n",
    "        AssertMeasurement([PauliZ], [q], Zero, \"qubit was not in |0⟩\");\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "{\"@type\":\"tuple\"}",
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%simulate CheckFreshQubitIsInZero"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When run on a simulator that supports it, [`AssertMeasurement`](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics.assertmeasurement) checks that **if** you were to measure `[q]` in the `[PauliZ]` basis, then it you would get the result `Zero` with **certainty**. Since the only state which always returns a measurement result of `Zero` when measured in the `PauliZ` basis is the $\\left|0\\right\\rangle$ state, passing the assertion tells us that our qubit is definitely in the $\\left|0\\right\\rangle$ state immediately afterwards.\n",
    "\n",
    "> ⚠ **NOTE**: This assertion critically depends on being able to violate the no-cloning theorem, since it checks a hypothetical measurement without actually performing that measurement.\n",
    "> That said, since the assertion has no effect on the state of the target machine, the assertion will automatically be ignored when run on simulators which don't support it, or on actual hardware that is bound by the no-cloning theorem.\n",
    "> This allows us to safely use assertions to check and validate assumptions when we can, while still allowing our Q# programs to work correctly across target machines.\n",
    "\n",
    "The same assertion can be used to check other conditions as well; for example, $H\\left|0\\right\\rangle = \\left|+\\right\\rangle$, so we would expect that if we apply the `H` operation to a fresh qubit, then our qubit will be in the $+1$ eigenstate of the $X$-basis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[\"CheckHPreparesPlus\"]",
      "text/html": [
       "<ul><li>CheckHPreparesPlus</li></ul>"
      ],
      "text/plain": [
       "CheckHPreparesPlus"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "operation CheckHPreparesPlus() : Unit {\n",
    "    using (q = Qubit()) {\n",
    "        within { H(q); }\n",
    "        apply {\n",
    "            AssertMeasurement([PauliX], [q], Zero, \"qubit was not in |+⟩\");\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "{\"@type\":\"tuple\"}",
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%simulate CheckHPreparesPlus"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Q# standard libraries also provide additional assertions built on top of [`AssertMeasurement`](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics.assertmeasurement) and [`AssertMeasurementProbability`](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics.assertmeasurementprobability) that can be convienent for working with different special cases and applications.\n",
    "\n",
    "For example, [`AssertOperationsEqualReferenced`](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics.assertoperationsequalreferenced) makes it easy to check whether two operations have the same effect on a register of qubits. We can use this operation to identities and simpliciations, such as that $(H \\otimes H) \\mathrm{CNOT}_{01} (H \\otimes H) = \\mathrm{CNOT}_{10}$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[\"ApplyCnotDirectly\",\"ApplyCnotWithinH\"]",
      "text/html": [
       "<ul><li>ApplyCnotDirectly</li><li>ApplyCnotWithinH</li></ul>"
      ],
      "text/plain": [
       "ApplyCnotDirectly, ApplyCnotWithinH"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "operation ApplyCnotDirectly(left : Qubit, right : Qubit) : Unit is Adj + Ctl {\n",
    "    CNOT(left, right);\n",
    "}\n",
    "\n",
    "operation ApplyCnotWithinH(left : Qubit, right : Qubit) : Unit is Adj + Ctl {\n",
    "    within {\n",
    "        ApplyToEachCA(H, [left, right]);\n",
    "    } apply {\n",
    "        CNOT(right, left);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[\"CheckCnotIdentity\"]",
      "text/html": [
       "<ul><li>CheckCnotIdentity</li></ul>"
      ],
      "text/plain": [
       "CheckCnotIdentity"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "operation CheckCnotIdentity() : Unit {\n",
    "    AssertOperationsEqualReferenced(2,\n",
    "        ApplyToFirstTwoQubitsCA(ApplyCnotDirectly, _),\n",
    "        ApplyToFirstTwoQubitsCA(ApplyCnotWithinH, _)\n",
    "    );\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "{\"@type\":\"tuple\"}",
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%simulate CheckCnotIdentity"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Similarly, the Microsoft.Quantum.Diagnostics namespace provides useful shorthands for commonly used assertions. For example, [`AssertQubit`](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics.assertqubit) makes it easy to assert measurement outcomes on a single qubit in the $Z$-basis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[\"CheckFreshQubitIsInZero\"]",
      "text/html": [
       "<ul><li>CheckFreshQubitIsInZero</li></ul>"
      ],
      "text/plain": [
       "CheckFreshQubitIsInZero"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "operation CheckFreshQubitIsInZero() : Unit {\n",
    "    using (q = Qubit()) {\n",
    "        AssertQubit(Zero, q);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "{\"@type\":\"tuple\"}",
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%simulate CheckFreshQubitIsInZero"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Allowances: Conditions on control flow"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The last kind of condition supported by the Q# standard libraries checks control flow within a segment of a Q# program. For example, if you want to make sure that your Q# program never allocates more than a given number of qubits, that can be checked using the [`AllowAtMostNQubits` operation](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics.allowatmostnqubits):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[\"CheckNoLargeRegistersAllocated\"]",
      "text/html": [
       "<ul><li>CheckNoLargeRegistersAllocated</li></ul>"
      ],
      "text/plain": [
       "CheckNoLargeRegistersAllocated"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "operation CheckNoLargeRegistersAllocated() : Unit {\n",
    "    within {\n",
    "        AllowAtMostNQubits(6, \"More than six qubits were allocated\");\n",
    "    } apply {\n",
    "        using (register = Qubit[7]) {\n",
    "            // ...\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\r\n",
       "                    <details>\r\n",
       "                        <summary>\r\n",
       "                            Unhandled exception of type Microsoft.Quantum.Simulation.Core.ExecutionFailException: 7 qubit(s) were allocated, but at most 6 qubit(s) are allowed:\n",
       "More than six qubits were allocated.\r\n",
       "                        </summary>\r\n",
       "                        <table>\r\n",
       "                            <thead>\r\n",
       "                                <tr>\r\n",
       "                                    <th>Source</th>\r\n",
       "                                    <th>Callable</th>\r\n",
       "                                </tr>\r\n",
       "                            </thead>\r\n",
       "\r\n",
       "                            <tbody>\r\n",
       "                                \r\n",
       "                        <tr>\r\n",
       "                            <td>(notebook)</td>\r\n",
       "                            <td>CheckNoLargeRegistersAllocated</td>\r\n",
       "                        </tr>\r\n",
       "                    \r\n",
       "                            </tbody>\r\n",
       "                        </table>\r\n",
       "                    </details>\r\n",
       "                "
      ],
      "text/plain": [
       "Unhandled exception. Microsoft.Quantum.Simulation.Core.ExecutionFailException: 7 qubit(s) were allocated, but at most 6 qubit(s) are allowed:\n",
       "More than six qubits were allocated.\r\n",
       " ---> SNIPPET.CheckNoLargeRegistersAllocated on C:\\snippet_.qs:line 0\r\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "7 qubit(s) were allocated, but at most 6 qubit(s) are allowed:\n",
      "More than six qubits were allocated.\r\n"
     ]
    }
   ],
   "source": [
    "%simulate CheckNoLargeRegistersAllocated"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Similarly, the [`AllowAtMostNCallsCA` operation](https://docs.microsoft.com/qsharp/api/qsharp/microsoft.quantum.diagnostics.allowatmostncallsca) can be used to ensure that a given operation is not called more than an allowed number of times:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "[\"CheckHNotCalled\"]",
      "text/html": [
       "<ul><li>CheckHNotCalled</li></ul>"
      ],
      "text/plain": [
       "CheckHNotCalled"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "operation CheckHNotCalled() : Unit {\n",
    "    within {\n",
    "        AllowAtMostNCallsCA(0, H, \"The H operation was called.\");\n",
    "    } apply {\n",
    "        using (q = Qubit()) {\n",
    "            H(q);\n",
    "            H(q);\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "{\"Subject\":\"Microsoft.Quantum.Intrinsic.H\",\"Sites\":[[\"Microsoft.Quantum.Intrinsic.H\"]]}",
      "text/html": [
       "\r\n",
       "                    <details>\r\n",
       "                        <summary>Calls to Microsoft.Quantum.Intrinsic.H:</summary>\r\n",
       "                        <ul>\r\n",
       "                                        <li><ul><li>Microsoft.Quantum.Intrinsic.H</li></ul></li>\r\n",
       "                                    </ul>\r\n",
       "                    </details>\r\n",
       "                "
      ],
      "text/plain": [
       "Calls to Microsoft.Quantum.Intrinsic.H:\\n\\n- Microsoft.Quantum.Intrinsic.H"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "Unhandled exception. Microsoft.Quantum.Simulation.Core.ExecutionFailException: Operation Microsoft.Quantum.Intrinsic.H was called more than the allowed 0 times:\n",
       "The H operation was called.\r\n",
       " ---> Microsoft.Quantum.Intrinsic.H on :line 0\r\n",
       "   at SNIPPET.CheckHNotCalled on C:\\snippet_.qs:line 0\r\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Operation Microsoft.Quantum.Intrinsic.H was called more than the allowed 0 times:\n",
      "The H operation was called.\r\n"
     ]
    }
   ],
   "source": [
    "%simulate CheckHNotCalled"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Epilogue"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/json": "{\"rows\":[{\"@type\":\"@tuple\",\"Item1\":\"iqsharp\",\"Item2\":\"0.12.20082513\"},{\"@type\":\"@tuple\",\"Item1\":\"Jupyter Core\",\"Item2\":\"1.4.0.0\"},{\"@type\":\"@tuple\",\"Item1\":\".NET Runtime\",\"Item2\":\".NETCoreApp,Version=v3.1\"}]}",
      "text/html": [
       "<table><thead><tr><th style=\"text-align: start;\">Component</th><th style=\"text-align: start;\">Version</th></tr></thead><tbody><tr><td style=\"text-align: start;\">iqsharp</td><td style=\"text-align: start;\">0.12.20082513</td></tr><tr><td style=\"text-align: start;\">Jupyter Core</td><td style=\"text-align: start;\">1.4.0.0</td></tr><tr><td style=\"text-align: start;\">.NET Runtime</td><td style=\"text-align: start;\">.NETCoreApp,Version=v3.1</td></tr></tbody></table>"
      ],
      "text/plain": [
       "Component    Version\r\n",
       "------------ ------------------------\r\n",
       "iqsharp      0.12.20082513\r\n",
       "Jupyter Core 1.4.0.0\r\n",
       ".NET Runtime .NETCoreApp,Version=v3.1\r\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%version"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Q#",
   "language": "qsharp",
   "name": "iqsharp"
  },
  "language_info": {
   "file_extension": ".qs",
   "mimetype": "text/x-qsharp",
   "name": "qsharp",
   "version": "0.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
